---
title: Scopes
---

import CodeBlock from "@theme/CodeBlock";
import asyncInitialization from "!!raw-loader!/docs/concepts/async_initialization.dart";
import themeScope from "!!raw-loader!/docs/concepts/theme_scope.dart";
import subtreeScope from "!!raw-loader!/docs/concepts/subtree_scope.dart";
import { trimSnippet } from "../../../../../src/components/CodeSnippet";
import { Link } from "../../../../../src/components/Link";

:::caution
The content of this page may be outdated.  
It will be updated in the future, but for now you may want to refer to the content
in the top of the sidebar instead (introduction/essentials/case-studies/...)
:::

Scoping in Riverpod is a very powerful feature, but like all powerful features, it should be used wisely and intentionally.

A few of the things that scoping enables are:

- Override the state of providers for a specific subtree (similar to how theming and `InheritedWidgets` work in flutter) [(see example)](#subtree-scope)
- Creating synchronous providers for normally async APIs [(see example)](#initialization-of-synchronous-provider-for-async-apis)
- Allowing `Dialog`s and `Overlay`s to inherit the state of providers from the widget subtree that cause them to be shown [(see example)](#showing-dialogs)
- Optimizing rebuilds of widgets by removing parameters from Widget constructors allowing you to make them `const`

If you are wanting to use scope for the first point, chances are you can use families instead.
Families have the advantages of allowing you to access each of those instances of the state from anywhere in the widget tree rather than just the state scoped to the specific subtree that you are in.

Using scope to create multiple instances of a provider's state is similar to how `package:provider` works.

However, using scope to accomplish that task, is more restrictive, as you cannot decide to access other instances from that scope.

As such, before scoping every provider you use, consider carefully why you want to scope the provider.

## ProviderScope and ProviderContainer

A scope is introduced by a [ProviderContainer]. This container holds the current state of all of your providers.
It manages the lookup and subscriptions between providers.

In Flutter you should use the [ProviderScope] widget, which contains a [ProviderContainer]
internally, and provides a way to access that container to the rest of the widget tree.

```dart
final valueProvider = StateProvider((ref) => 0);

// DO this
void main() {
  runApp(ProviderScope(child: MyApp()));
}

//DON'T do this:
final myProviderContainer = ProviderContainer();
void main(){
  runApp(MyApp());
}
```

:::warning
Do not use multiple [ProviderContainer]s, without an understanding of how they work.
Each will have it's own separate thread of states, which will not be able to access each other.
Tests are an example of when you might want to use separate [ProviderContainer]s
in order to make each test's state independent of the others.
:::

Only create a [ProviderContainer] without a [ProviderScope] for testing and dart-only usage.

## How Riverpod Finds a Provider

When a widget or provider requests the value of a provider, Riverpod looks up the state of that provider in the nearest
[ProviderScope] widget. If neither the provider nor one of it's explicitly listed dependencies is overridden in that scope Riverpod continues it's lookup up the widget tree.
If the provider has not been overridden in any Widget subtrees the lookup defaults to the [ProviderContainer] in the root [ProviderScope].

Once this process locates the scope in which the provider should reside it determines if the provider has been created yet.
If so, it will return the state of the provider.
However, if the provider has been invalidated or is not currently initialized it will create the state using the provider's build method.

## Initialization of Synchronous Provider for Async APIs

Often you might have some async initialization of a dependency such as `SharedPreferences` or `FirebaseApp`.
Many other providers might rely on this, and dealing with the error / loading states in each of those providers is redundant.

You might be able to guarantee that those providers will not have errors and will load quickly when the app is started.

So how do you makes these sorts of provider states available synchronously?

Here is an example that shows how scoping allows you override a dummy provider when your asynchronous API is ready.

## Subtree Scoping

Scoping allows you to override the state of a provider for a specific subtree of your widget tree.
In this way it can provide a similar mechanism to `InheritedWidget` from flutter, or the providers from `package:provider`.

For example, in flutter you can override the `Theme` for a particular subtree of your widget tree, by wrapping it in a `Theme` widget.

<CodeBlock>{trimSnippet(themeScope)}</CodeBlock>

Under the hood, `Theme` is an `InheritedWidget` and when widgets look up the `Theme` they get the `Theme` from the nearest `Theme` widget above it in the widget tree.

Riverpod works differently, since all of the state of your application is typically stored in a root [ProviderScope] widget.
Don't worry, this doesn't cause your whole application to rebuild when the state changes, it just allows you to access the state from anywhere in your widget tree.

What if you want different providers depending on which page you are in?

The first thing that you should consider is whether the provided behavior will differ in any way.

If so -> just create a new provider with a different name and use it in that page

If not -> Consider using a <Link documentID="concepts/modifiers/family"/>.

Often you start by thinking that you only need a provider on a particular page, but end up wanting to use it in another page later on.
Families protect you against this eventuality, and are a major difference in how you should adjust your thinking if you are coming from `package:provider`.

If families really do not fit your use case, the following example shows you how to override a provider for a particular subtree.

<CodeBlock>{trimSnippet(subtreeScope)}</CodeBlock>

## When to choose Scoped Providers or Families

While scopes are important to understand, it is easy to get carried away when using scopes.

If you want a different instance of a provider's state depending on where it is in the widget tree you have a few alternatives available to you: `Scoping`, `Families`, or a combination.
The appropriate choice depends on your use case.

Families:

- Pro: You can show multiple of the states no matter which subtree you are in
- Pro: This makes it a more flexible and scalable solution for many use cases

Scoping:

- Con: You end up with more nesting of [ProviderScope] widgets in your widget tree
- Con: You can only access the one override in your section of the widget tree
- Con: You end up having to explicitly list the dependencies of most of your providers
- Pro: You can reduce the number of parameters in your widget constructors
- Pro: You get a slight performance advantage, and can potentially make some of your widget constructors `const`

Using a combination of the two approaches, you can get the pros of both approaches, but you still have to deal with the cons of scoping.

:::warning
Remember that scopes introduce a new instance of the state of every provider that is overridden or has listed a dependency on a provider that was overridden.
If you override with the same parameter in a different subtree of the app, it will **not** be the same instance of the provider's state.
Families are more flexible in general, and with the upcoming code generation feature it is easy to use multiple parameters for a family.
Often a good combination is to use both families and scoping. Use a family to provide general access to a piece of state anywhere in your app, and then use scoping to
provide a specific instance of the family's state depending on where you are in the widget tree.
:::

### Less common usages of Scopes

Sometimes you may want to override a whole set of providers in a specific subtree of your app.
By listing a common provider in the dependencies list of each of those providers, you can easily create new states for all of them at once, by overriding the common one.

Note that if you try to use families for this, you will end up with many families that all have the same parameter, and you could end up passing that parameter all over the widget tree.
In this case it is also acceptable to use scopes.

:::warning
Once you start using scope, make sure to always list your dependencies and keep them up to date, to prevent runtime exceptions.
To help with this we have created [riverpod_lint] which will warn you if there is a missing dependency.
Additionally with [riverpod_generator] the code generator automatically generates the dependency list.
:::

[ProviderContainer]: https://pub.dev/documentation/riverpod/latest/riverpod/ProviderContainer-class.html
[ProviderScope]: https://pub.dev/documentation/flutter_riverpod/latest/flutter_riverpod/ProviderScope-class.html
[riverpod_lint]: https://github.com/rrousselGit/riverpod/tree/master/packages/riverpod_lint
[riverpod_generator]: https://github.com/rrousselGit/riverpod/tree/master/packages/riverpod_generator
